package com.yupi.springbootinit.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.AI.SDK.Client.AIClient;
import com.ai.common.model.BIRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.yupi.springbootinit.BiMQ.BiMq.BiMessageProducer;
import com.yupi.springbootinit.annotation.AuthCheck;
import com.yupi.springbootinit.annotation.LogAnnotation;
import com.yupi.springbootinit.common.BaseResponse;
import com.yupi.springbootinit.common.DeleteRequest;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.common.ResultUtils;
import com.yupi.springbootinit.component.WebSocketServer;
import com.yupi.springbootinit.constant.CommonConstant;
import com.yupi.springbootinit.constant.UserConstant;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.exception.ThrowUtils;
import com.yupi.springbootinit.manager.AIManager;
import com.yupi.springbootinit.manager.RedisLimiterManager;
import com.yupi.springbootinit.model.dto.chartInfo.ChartInfoAddRequest;
import com.yupi.springbootinit.model.dto.chartInfo.ChartInfoQueryRequest;
import com.yupi.springbootinit.model.dto.chartInfo.ChartInfoUpdateRequest;
import com.yupi.springbootinit.model.dto.count.QueryCountRequest;
import com.yupi.springbootinit.model.entity.CallAndGenerateCounts;
import com.yupi.springbootinit.model.entity.ChartInfo;
import com.yupi.springbootinit.model.entity.GenHistory;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.model.vo.CallAndGenerateCountsVO;
import com.yupi.springbootinit.model.vo.ChartInfoVO;
import com.yupi.springbootinit.service.CallAndGenerateCountsService;
import com.yupi.springbootinit.service.ChartInfoService;
import com.yupi.springbootinit.service.GenHistoryService;
import com.yupi.springbootinit.service.UserService;
import com.yupi.springbootinit.utils.ExcelUtils;
import com.yupi.springbootinit.utils.RedisUtils;
import com.yupi.springbootinit.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 帖子接口
 *
" " 
 */
@RestController
@RequestMapping("/chart")
@Slf4j
public class chartController {

    @Resource
    private ChartInfoService chartInfoService;

    @Resource
    private UserService userService;

    @Resource
    private AIManager aiManager;

    @Resource
    private RedisLimiterManager redisLimiterManager;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private BiMessageProducer biMessageProducer;

    @Resource
    private AIClient aiClient;

    private static String Identity = "数据分析师";

    private static Long ModelId = 1659171950288818178L;

    private StringBuilder userInput;

    @Resource
    private WebSocketServer webSocketServer;


    @Resource
    private RedisUtils redisUtils;

    @Resource
    private CallAndGenerateCountsService countsService;


    @Resource
    private GenHistoryService genHistoryService;


    /*
     * 生成图表的方法
     * */
    @PostMapping("/gen")
    public BaseResponse<ChartInfoVO> gen(@RequestPart("file") MultipartFile multipartFile,
                                         ChartInfoAddRequest chartInfoAddRequest, HttpServletRequest httpServletRequest) {
        User user = userService.getLoginUser(httpServletRequest,httpServletRequest.getHeader("token"));
        //用户请求限流,为了加以区分我们用方法名作为yikey
        redisLimiterManager.doRateLimit("gen_" + String.valueOf(user.getId()));
        String goal = chartInfoAddRequest.getGoal();
        String charName = chartInfoAddRequest.getName();
        String chartType = chartInfoAddRequest.getChartType();
        //分析目标不能为空，为空则报错
        ThrowUtils.throwIf(StringUtils.isBlank(goal), new BusinessException(ErrorCode.PARAMS_ERROR, "分析目标不能为空"));
        //图表名称若不为空，并且长度大于100就提示错误
        ThrowUtils.throwIf(StringUtils.isNotBlank(charName) && charName.length() > 100,
                new BusinessException(ErrorCode.PARAMS_ERROR, "分析名称过长"));
        //对大小进行限制 1M
        long size = multipartFile.getSize();
        final long ONE_MB = 1024 * 1024L;
        ThrowUtils.throwIf(size > ONE_MB, ErrorCode.PARAMS_ERROR, "文件超过1M");
        //对用户上传文件进行校验
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        List<String> stringList = Collections.singletonList("xlsx");
        ThrowUtils.throwIf(!stringList.contains(suffix), new BusinessException(ErrorCode.PARAMS_ERROR, "文件名后缀不符合"));
        //将文件转为CSV格式字符串
        String data = ExcelUtils.excelToCsv(multipartFile);
        // 构造用户输入
        userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        // 拼接分析目标
        String userGoal = goal;
        // 如果图表类型不为空
        if (StringUtils.isNotBlank(chartType)) {
            // 就将分析目标拼接上“请使用”+图表类型
            userGoal += "，请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        userInput.append(data).append("\n");
        String result = aiManager.doChart(ModelId, userInput.toString());
        ThrowUtils.throwIf(StringUtils.isBlank(result), new BusinessException(ErrorCode.SYSTEM_ERROR, "图表保存失败"));
        String[] splits = result.split("【【【【【");
        // 拆分之后还要进行校验
        if (splits.length < 3) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "AI 生成错误");
        }
        //拆分出来后的内容
        String chartCode = splits[1].trim();
        String chartResult = splits[2].trim();
        //存入数据库中
        ChartInfo chartInfo = new ChartInfo();
        chartInfo.setGoal(goal);
        chartInfo.setCharData(data);
        chartInfo.setName(charName);
        chartInfo.setCharType(chartType);
        chartInfo.setGenChart(chartCode);
        chartInfo.setGenResult(chartResult);
        chartInfo.setUserId(user.getId());
        chartInfo.setStatus("succeed");
        boolean save = chartInfoService.save(chartInfo);
        ThrowUtils.throwIf(!save, new BusinessException(ErrorCode.SYSTEM_ERROR, "图表保存失败"));
        //构建返回对象，并且设置值
        ChartInfoVO chartInfoVO = new ChartInfoVO();
        chartInfoVO.setGenChart(chartCode);
        chartInfoVO.setGenResult(chartResult);
        chartInfoVO.setChartId(chartInfo.getId());
        return ResultUtils.success(chartInfoVO);
    }

    /**
     * 异步调用生成图表方法
     * @param multipartFile  源数据
     * @param chartInfoAddRequest  图表添加请求对象
     * @param httpServletRequest    servlet
     * @return   视图对象
     */
    @PostMapping("/gen/async")
    public BaseResponse<ChartInfoVO> genAsync(@RequestPart("file") MultipartFile multipartFile,
                                              ChartInfoAddRequest chartInfoAddRequest, HttpServletRequest httpServletRequest) {
        User user = userService.getLoginUser(httpServletRequest,httpServletRequest.getHeader("token"));
        //用户请求限流,为了加以区分我们用方法名作为yikey
        redisLimiterManager.doRateLimit("gen_" + String.valueOf(user.getId()));
        String goal = chartInfoAddRequest.getGoal();
        String charName = chartInfoAddRequest.getName();
        String chartType = chartInfoAddRequest.getChartType();
        //分析目标不能为空，为空则报错
        ThrowUtils.throwIf(StringUtils.isBlank(goal), new BusinessException(ErrorCode.PARAMS_ERROR, "分析目标不能为空"));
        //图表名称若不为空，并且长度大于100就提示错误
        ThrowUtils.throwIf(StringUtils.isNotBlank(charName) && charName.length() > 100,
                new BusinessException(ErrorCode.PARAMS_ERROR, "分析名称过长"));
        //对大小进行限制 1M
        long size = multipartFile.getSize();
        final long ONE_MB = 1024 * 1024L;
        ThrowUtils.throwIf(size > ONE_MB, ErrorCode.PARAMS_ERROR, "文件超过1M");
        //对用户上传文件进行校验
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        List<String> stringList = Collections.singletonList("xlsx");
        ThrowUtils.throwIf(!stringList.contains(suffix), new BusinessException(ErrorCode.PARAMS_ERROR, "文件名后缀不符合"));
        //将文件转为CSV格式字符串
        String data = ExcelUtils.excelToCsv(multipartFile);
        // 构造用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        // 拼接分析目标
        String userGoal = goal;
        // 如果图表类型不为空
        if (StringUtils.isNotBlank(chartType)) {
            // 就将分析目标拼接上“请使用”+图表类型
            userGoal += "，请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        userInput.append(data).append("\n");
        //校验通过以后，先存入到数据库中
        ChartInfo chartInfo = new ChartInfo();
        chartInfo.setGoal(goal);
        chartInfo.setCharData(data);
        chartInfo.setName(charName);
        chartInfo.setCharType(chartType);
        chartInfo.setUserId(user.getId());
        chartInfo.setStatus("wait");
        boolean save = chartInfoService.save(chartInfo);
        ThrowUtils.throwIf(!save, new BusinessException(ErrorCode.SYSTEM_ERROR, "图表保存失败"));
        // 意味着已经调用了，可以直接+1
        QueryCountRequest request = new QueryCountRequest();
        request.setUserId(user.getId());
        CallAndGenerateCountsVO countsVO = countsService.queryCount(request);
        CallAndGenerateCounts counts = new CallAndGenerateCounts();
        BeanUtils.copyProperties(countsVO,counts);
        countsService.updateCount(counts);
        // 调用AI服务进行改造，
        try {
            CompletableFuture.runAsync(() -> {
                // 先修改数据库中的数据的状态改为running，
                ChartInfo info = new ChartInfo();
                info.setId(chartInfo.getId());
                info.setStatus("running");
                //如果修改失败就意味着数据库出现问题了，如果修改失败了，也要向数据库中存储信息，将status状态改为failed,这里直接抽象成一个
                boolean updateResult = chartInfoService.updateById(info);
                // 公用的方法
                if (!updateResult){
                    handleUpdateError(chartInfo.getId(),"更新图表状态失败");
                    return;
                }
                //调用AI
                String result = aiManager.doChart(ModelId, userInput.toString());
                String[] splits = result.split("【【【【【");
                // 拆分之后还要进行校验
                if (splits.length < 3) {
                    handleUpdateError(chartInfo.getId(),"AI 生成图表错误");
                    return;
                }
                //拆分出来后的内容
                String chartCode = splits[1].trim();
                String chartResult = splits[2].trim();
                //当AI生成成功以后继续更新数据库图表的内容并且，更新状态为成功
                ChartInfo updateChartInfo = new ChartInfo();
                updateChartInfo.setId(chartInfo.getId());
                updateChartInfo.setStatus("succeed");
                updateChartInfo.setGenChart(chartCode);
                updateChartInfo.setGenResult(chartResult);
                //todo 这里要向历史记录表中插入
                GenHistory genHistory = new GenHistory();
                genHistory.setGenName(charName);
                genHistory.setUserId(user.getId());
                genHistory.setChartId(chartInfo.getId());
                genHistoryService.save(genHistory);
                //改变次数
                Integer remainTasks = counts.getRemainTasks();
                remainTasks = remainTasks-1;
                counts.setRemainTasks(remainTasks);
                countsService.updateById(counts);
                boolean updateResult2 = chartInfoService.updateById(updateChartInfo);
                try {
                    webSocketServer.sendInfo(updateChartInfo.getStatus(),user.getId());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (!updateResult2){
                    handleUpdateError(chartInfo.getId(),"更新图表状态失败");
                }
                //这个参数是☞在哪个线程池中执行
            }, threadPoolExecutor);
        } catch (Exception e) {
            // todo 后期可以改为具体异常抛出
            throw new BusinessException(ErrorCode.FORBIDDEN_ERROR,"队列已满，请求繁忙请稍后！！");
        }
        //构建返回对象，并且设置值
        ChartInfoVO chartInfoVO = new ChartInfoVO();
        chartInfoVO.setChartId(chartInfo.getId());
        return ResultUtils.success(chartInfoVO);
    }

    /**
     * mq调用生成图表方法
     *
     * @param multipartFile       源数据
     * @param chartInfoAddRequest 图表添加请求对象
     * @param httpServletRequest  servlet
     * @return 视图对象
     */
    @PostMapping("/gen/async/mq")
    @LogAnnotation(module = "异步生成图表",operator = "图表内容")
    public BaseResponse genAsyncMq(@RequestPart("file") MultipartFile multipartFile,
                                   ChartInfoAddRequest chartInfoAddRequest, HttpServletRequest httpServletRequest) throws InterruptedException {
        User user = userService.getLoginUser(httpServletRequest,httpServletRequest.getHeader("token"));
        //用户请求限流,为了加以区分我们用方法名作为yikey
        redisLimiterManager.doRateLimit("gen_" + String.valueOf(user.getId()));
        String goal = chartInfoAddRequest.getGoal();
        String charName = chartInfoAddRequest.getName();
        String chartType = chartInfoAddRequest.getChartType();
        //分析目标不能为空，为空则报错
        ThrowUtils.throwIf(StringUtils.isBlank(goal), new BusinessException(ErrorCode.PARAMS_ERROR, "分析目标不能为空"));
        //图表名称若不为空，并且长度大于100就提示错误
        ThrowUtils.throwIf(StringUtils.isNotBlank(charName) && charName.length() > 100,
                new BusinessException(ErrorCode.PARAMS_ERROR, "分析名称过长"));
        //对大小进行限制 1M
        long size = multipartFile.getSize();
        final long ONE_MB = 1024 * 1024L;
        ThrowUtils.throwIf(size > ONE_MB, ErrorCode.PARAMS_ERROR, "文件超过1M");
        //对用户上传文件进行校验
        String filename = multipartFile.getOriginalFilename();
        String suffix = FileUtil.getSuffix(filename);
        List<String> stringList = Collections.singletonList("xlsx");
        ThrowUtils.throwIf(!stringList.contains(suffix), new BusinessException(ErrorCode.PARAMS_ERROR, "文件名后缀不符合"));
        //将文件转为CSV格式字符串
        String data = ExcelUtils.excelToCsv(multipartFile);
        //校验通过以后，先存入到数据库中
        //获取当前时间戳
        // 意味着已经调用了，可以直接+1
        QueryCountRequest request = new QueryCountRequest();
        request.setUserId(user.getId());
        CallAndGenerateCountsVO countsVO = countsService.queryCount(request);
        CallAndGenerateCounts counts = new CallAndGenerateCounts();
        BeanUtils.copyProperties(countsVO,counts);
        try {
            //todo 这里一旦涉及到修改，采用Redis延迟双删策略
            redisUtils.delCacheMapValue(user.getId().toString(),user.getId().toString());
            countsService.updateCount(counts);
        } catch (Exception e) {
            return ResultUtils.error(ErrorCode.OPERATION_ERROR,e.getMessage());
        }
        Thread.sleep(30);
        redisUtils.delCacheMapValue(user.getId().toString(),user.getId().toString());
        //生成sql语句创建表，并且执行sql语句
        //将表格中的数据保存到数据库
        ChartInfo chartInfo = new ChartInfo();
        chartInfo.setGoal(goal);
        chartInfo.setCharData(data);
        chartInfo.setName(charName);
        chartInfo.setCharType(chartType);
        chartInfo.setUserId(user.getId());
        chartInfo.setStatus("running");
        boolean save = chartInfoService.save(chartInfo);
        ThrowUtils.throwIf(!save, new BusinessException(ErrorCode.SYSTEM_ERROR, "图表保存失败"));
        Long chartInfoId = chartInfo.getId();
        String message = chartInfoId +","+user.getId()+","+counts.getId();
        //todo 这里要向历史记录表中插入
        GenHistory genHistory = new GenHistory();
        genHistory.setGenName(charName);
        genHistory.setUserId(user.getId());
        genHistory.setChartId(chartInfo.getId());
        genHistoryService.save(genHistory);
        //调用消息生产者代码
        //消息生产者
        biMessageProducer.sendMessage(message);
        //构建返回对象，并且设置值
        ChartInfoVO chartInfoVO = new ChartInfoVO();
        chartInfoVO.setChartId(chartInfo.getId());
        return ResultUtils.success(chartInfoVO);
    }

    /**
     * 统一处理更新图表信息数据失败方法
     * @param chartId    图表ID
     * @param execMessage  失败信息
     */
    private void handleUpdateError(Long chartId, String execMessage) {
        ChartInfo updateChartInfo = new ChartInfo();
        updateChartInfo.setId(chartId);
        updateChartInfo.setStatus("failed");
        updateChartInfo.setExecMessage(execMessage);
        boolean b = chartInfoService.updateById(updateChartInfo);
        ThrowUtils.throwIf(!b,new BusinessException(ErrorCode.SYSTEM_ERROR,"更新图表失败状态失败"));
    }

    //todo 失败数据重试生成接口
    @PostMapping("/retry/gen/Chart")
    public BaseResponse<ChartInfoVO> retryGenAsync(@RequestBody ChartInfoQueryRequest chartInfoQueryRequest,HttpServletRequest httpServletRequest){
        User user = userService.getLoginUser(httpServletRequest,httpServletRequest.getHeader("token"));
        //todo 根据图表ID 去缓存中查询，若存在则放入到队列当中
        ThrowUtils.throwIf(chartInfoQueryRequest.getId()==null,
                new BusinessException(ErrorCode.PARAMS_ERROR,"必须传入图表ID"));
        Long chartId = chartInfoQueryRequest.getId();
        String stringKey = redisUtils.getStringKey(chartId.toString( ));
        ThrowUtils.throwIf(stringKey==null,
                new BusinessException(ErrorCode.OPERATION_ERROR,"时间已过期无法重试"));
        //从缓存中查出来更新状态
        ChartInfo chartInfo = JSONUtil.toBean(stringKey, ChartInfo.class);
        Long chartInfoId = chartInfo.getId();
        chartInfo.setStatus("running");
        biMessageProducer.sendMessage(chartInfoId.toString()+","+user.getId());
        ChartInfoVO chartInfoVO = new ChartInfoVO();
        BeanUtils.copyProperties(chartInfoVO,chartInfo);
        return ResultUtils.success(chartInfoVO);
    }




    /**
     * 创建
     *
     * @param chartInfoAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addPost(@RequestBody ChartInfoAddRequest chartInfoAddRequest, HttpServletRequest request) {
        if (chartInfoAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        ChartInfo chartInfo = new ChartInfo();
        BeanUtils.copyProperties(chartInfoAddRequest, chartInfo);
        User loginUser = userService.getLoginUser(request,request.getHeader("token"));
        chartInfo.setUserId(loginUser.getId());
        boolean result = chartInfoService.save(chartInfo);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        long newPostId = chartInfo.getId();
        return ResultUtils.success(newPostId);
    }

    /**
     * 删除
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/my/chart/delete")
    public BaseResponse<Boolean> deletePost(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = userService.getLoginUser(request,request.getHeader("token"));
        long id = deleteRequest.getId();
        // 判断是否存在
        ChartInfo oldPost = chartInfoService.getById(id);
        ThrowUtils.throwIf(oldPost == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可删除
        if (!oldPost.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
//        boolean b = chartInfoService.removeById(id);
        UpdateWrapper<ChartInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",deleteRequest.getId());
        updateWrapper.set("is_delete",1);
        boolean b = chartInfoService.update(updateWrapper);
        return ResultUtils.success(b);
    }

    /**
     * 更新（仅管理员）
     *
     * @param chartInfoUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updatePost(@RequestBody ChartInfoUpdateRequest chartInfoUpdateRequest) {
        if (chartInfoUpdateRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        ChartInfo chartInfo = new ChartInfo();
        BeanUtils.copyProperties(chartInfoUpdateRequest, chartInfo);
        boolean result = chartInfoService.updateById(chartInfo);
        return ResultUtils.success(result);
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param chartInfoQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page")
    public BaseResponse<Page<ChartInfo>> listMyChartPage(@RequestBody ChartInfoQueryRequest chartInfoQueryRequest,
                                                         HttpServletRequest request) {
        if (chartInfoQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request,request.getHeader("token"));
        chartInfoQueryRequest.setUserId(loginUser.getId());
        long current = chartInfoQueryRequest.getCurrent();
        long size = chartInfoQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<ChartInfo> chartInfoPage = chartInfoService.page(new Page<>(current, size),
                getQueryWrapper(chartInfoQueryRequest));
        return ResultUtils.success(chartInfoPage);
    }

    @PostMapping("/my/chart/info")
    public BaseResponse<ChartInfo> queryMyChartDetail(@RequestBody ChartInfoQueryRequest chartInfoQueryRequest,
                                                         HttpServletRequest request) {
        if (chartInfoQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request,request.getHeader("token"));
        Long userId = loginUser.getId();
        QueryWrapper<ChartInfo> wrapper = new QueryWrapper<>();
        Long id = chartInfoQueryRequest.getId();
        wrapper.eq(id != null && id > 0, "id", id);
        wrapper.eq("is_delete", 0);
        wrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        return ResultUtils.success(chartInfoService.getOne(wrapper));
    }

    //调用SDK接口
    @PostMapping("/invoke/AI")
    public BaseResponse<String> invokeAI(@RequestBody BIRequest biRequest){
        String csvData = biRequest.getCsvData();
        String result = aiClient.invokeAI(csvData,biRequest.getChartName(), biRequest.getGoal(),biRequest.getChartType());
        return ResultUtils.success(result);
    }
    /**
     * 获取查询包装类
     *
     * @param chartQueryRequest
     * @return
     */
    private QueryWrapper<ChartInfo> getQueryWrapper(ChartInfoQueryRequest chartQueryRequest) {
        QueryWrapper<ChartInfo> queryWrapper = new QueryWrapper<>();
        if (chartQueryRequest == null) {
            return queryWrapper;
        }
        Long id = chartQueryRequest.getId();
        String name = chartQueryRequest.getName();
        String goal = chartQueryRequest.getGoal();
        String chartType = chartQueryRequest.getChartType();
        Long userId = chartQueryRequest.getUserId();
        String sortField = chartQueryRequest.getSortField();
        String sortOrder = chartQueryRequest.getSortOrder();

        queryWrapper.eq(id != null && id > 0, "id", id);
        queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
        queryWrapper.eq(StringUtils.isNotBlank(goal), "goal", goal);
        queryWrapper.eq(StringUtils.isNotBlank(chartType), "chart_type", chartType);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        queryWrapper.eq("is_delete", 0);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }



    public static void main(String[] args) {
        test();
    }
    private static int count = 0;
    static int test2(int num){
        count++;
        System.out.println("当前执行的第"+count+"次num:"+num);
        if(num<=0){
            throw new IllegalArgumentException("0异常！！！");
        }
        return num;
    }
    static void test() {
        //这里应该封装为方法，
        //1:RetryerBuilder 构造重试器
        Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                //2：设置任何异常都重试
                .retryIfRuntimeException()
                //3:根据返回结果重试,只要是偶数就重试
                .retryIfResult(result -> result % 2 == 0)
                //4：设置重试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();
        //6：调用call方法。
        try {
            retryer.call(()->test2(0));
        } catch (ExecutionException | RetryException e) {
            System.out.println("异常："+e.getMessage());
        }

        try {
            retryer.call(()->test2(1));
        } catch (ExecutionException | RetryException e) {
            System.out.println("异常："+e.getMessage());
        }

        try {
            retryer.call(()->test2(4));
        } catch (ExecutionException | RetryException e) {
            System.out.println("偶数异常："+e.getMessage());
        }
    }


}
